package com.gsdl.model.bo;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.NoResultException;
import javax.persistence.Persistence;
import javax.persistence.PersistenceUnit;

import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.ejb.HibernateEntityManagerFactory;

import com.gsdl.model.entity.BaseEntity;

// TODO: Auto-generated Javadoc
/**
 * The Class BaseBO.
 * 
 * Super class for all BOs, where common operations are
 *
 * @param <T> the generic type that extends from the base entity
 * @author Natacha Antonopoulos
 */
public class BaseBO<T extends BaseEntity> {
    

	/** The Constant LOG. */
	private static final Logger LOG = Logger.getLogger(BaseBO.class.getName());
	
	
    /** The emf. */
    @PersistenceUnit(unitName = "gsdlPU")
    EntityManagerFactory emf = null;
    
    /** The entity. */
    private T entity;
    
    /**
     * Instantiates a new base bo.
     *
     * @param entity the entity
     */
    BaseBO(T entity){
    	this.entity = entity;
    }
    
	/**
	 * Save.
	 *
	 * @param entity the entity
	 * @return the save entity
	 */
	public T save(T entity){
		EntityManager em = null;
		try {
	        em = getEntityManager();
	        EntityTransaction etx = em.getTransaction();
	        etx.begin();
	       
	        if(entity.getId() == null)
	        	em.persist(entity);
	        else
	        	em.merge(entity);
	        
	        em.flush();
	
	        etx.commit();
	//        closeSession(em);
	        return entity;
		}catch (Exception ex) {
	        ex.printStackTrace();
	    }finally{
	    	
	    	closeSession(em);
	    }
	
		return null;  
            
	}
	
	/**
	 * Removes the.
	 *
	 * @param entity the entity
	 */
	public void remove(T entity){
		EntityManager em = null;
		try {
	        em = getEntityManager();
	        EntityTransaction etx = em.getTransaction();
	        etx.begin();
	       
	        
	        em.remove(em.contains(entity) ? entity : em.merge(entity));
	
	        em.flush();
	
	        etx.commit();
//	        closeSession(em);
		}catch (Exception ex) {
	        ex.printStackTrace();
	    }finally{
	    	
	    	closeSession(em);
	    }
		
	}
	
	/**
	 * Save entity.
	 *
	 * @param <V> the value type
	 * @param entity the entity
	 * @return the v
	 */
	public <V extends BaseEntity> V saveEntity(V entity){
		EntityManager em = null;
		
		try {
	        em = getEntityManager();
	        EntityTransaction etx = em.getTransaction();
	        etx.begin();
	       
	        if(entity.getId() == null)
	        	em.persist(entity);
	        else
	        	em.merge(entity);
	        
	        em.flush();
	
	        etx.commit();
//	        closeSession(em);
	        return entity;
		}catch (Exception ex) {
	        ex.printStackTrace();
	    }finally{
	    	
	    	closeSession(em);
	    }
		return null;      
	}
	
	/**
	 * Gets the by id.
	 *
	 * @param id the id
	 * @return the by id
	 */
	@SuppressWarnings("unchecked")
	public T getById(Long id){
		EntityManager em = null;
        try {
           
        	em = getEntityManager();
            T t = (T)em.find(entity.getClass(), id);            
//            closeSession(em);
            return t;
            
        }catch (Exception ex) {
            ex.printStackTrace();
        }finally{
        	
        	closeSession(em);
        }
        
		return null;
	}
    
    /**
     * Gets the all.
     *
     * @return the all
     */
    @SuppressWarnings("unchecked")
	public List<T> getAll(){
		EntityManager em = null;
        try {
        	
            em = getEntityManager();
            LOG.info("SELECT obj FROM " + entity.getClass().getSimpleName() + " obj");
            List<T> list = (List<T>)em.createQuery("SELECT obj FROM " + entity.getClass().getSimpleName() + " obj").getResultList();
            return list;
            
        } catch (NoResultException ex) {
            ex.printStackTrace();
        }catch (Exception ex) {
            ex.printStackTrace();
        }finally{
        	
        	closeSession(em);
        }
		return null;
	}
    
    /**
     * Gets the all.
     *
     * @param <V> the value type
     * @param _class the _class
     * @return the all
     */
    @SuppressWarnings("unchecked")
	public <V> List<V> getAll(Class<V> _class){
		EntityManager em = null;
        try {
        	
            em = getEntityManager();
            List<V> list = (List<V>)em.createQuery("SELECT obj FROM " + _class.getSimpleName() + " obj").getResultList();
//            closeSession(em);
            return list;
            
        } catch (NoResultException ex) {
            ex.printStackTrace();
        }catch (Exception ex) {
            ex.printStackTrace();
        }finally{
        	
        	closeSession(em);
        }
        
		return null;
	}
    
    
    
    /**
     * Gets the entity manager.
     *
     * @return the entity manager
     */
    EntityManager getEntityManager() {
		if(emf == null)
			emf = Persistence.createEntityManagerFactory("gsdlPU");
		EntityManager entityManager = emf.createEntityManager();

        return entityManager;
    }
    
    /**
     * Gets the session factory.
     *
     * @return the session factory
     */
    SessionFactory getSessionFactory() {
    	 emf = Persistence.createEntityManagerFactory("gsdlPU");
		return ((HibernateEntityManagerFactory) emf).getSessionFactory();
	}
    
    /**
     * Gets the session.
     *
     * @return the session
     */
    Session getSession() {
    	Session session = getSessionFactory().getCurrentSession();
        return session;
    }

    
    /**
     * Close session.
     *
     * @param entityManager the EntityManager
     */
    void closeSession(EntityManager entityManager){
    	if(entityManager != null)
    		entityManager.close();
    }
    
	/**
	 * Gets the entity.
	 *
	 * @return the entity
	 */
	public T getEntity() {
		return entity;
	}

	/**
	 * Sets the entity.
	 *
	 * @param entity the new entity
	 */
	public void setEntity(T entity) {
		this.entity = entity;
	}

    
}
